package org.gitman.agentplatform.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

import org.gitman.agentplatform.core.PersistenceManager;
import org.gitman.agentplatform.core.PlatformManager;
import org.gitman.agentplatform.ui.actions.ActionsManager;
import org.gitman.agentplatform.ui.graph.GraphDisplPanel;
import org.gitman.agentplatform.ui.graph.GraphEditor;
import org.gitman.agentplatform.ui.graph.GraphPanel;
import org.gitman.agentplatform.ui.simulation.SimulationPanel;
import org.gitman.agentplatform.ui.summary.AgentSummaryDetailsPanel;
import org.gitman.agentplatform.ui.summary.SummaryPanel;
import org.gitman.agentplatform.ui.utils.LoggingPanel;
import org.w3c.dom.Document;

import com.mxgraph.io.mxCodec;
import com.mxgraph.util.mxCellRenderer;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxXmlUtils;
import com.mxgraph.util.png.mxPngEncodeParam;
import com.mxgraph.util.png.mxPngImageEncoder;
import com.mxgraph.util.png.mxPngTextDecoder;
import com.mxgraph.view.mxGraph;

public class MainFrame extends JFrame implements WindowListener{
	
	private String viewConfig;
	public static String TITLE = "Agent Platform";
	public static String VER = "ver 1.1";
	private static MainFrame mainFrame;
	private GraphPanel graphPanel;
	private SimulationPanel simulationPanel;
	private SummaryPanel summaryPanel;
	private JTabbedPane optionsTabbedPane;
	private GraphDisplPanel graphDisplPanel;
	private ActionsManager actionsManager;
	private LoggingPanel loggingPanel;
	private JPanel mainPanel;
	private AgentSummaryDetailsPanel agentSummaryDetailsPanel;
		
	public MainFrame(){
		mainFrame = this;
		viewConfig = System.getProperty("viewConfig");
		init();
		createMenu();
		createContent();
	}
	private void init(){
		try {
			Properties properties = new Properties();
			setTitle(TITLE + " " + VER);
			properties.load(new FileInputStream(viewConfig));
			Integer width = Integer.parseInt(properties.get("mainFrame.width").toString());
			Integer height = Integer.parseInt(properties.get("mainFrame.height").toString());
			Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
			setLocation((dim.width - width)/2, (dim.height - height)/2);
			setSize(width, height);
			String laf = properties.getProperty("mainFrame.laf");
			UIManager.setLookAndFeel(laf);
			addWindowListener(this);
			actionsManager = new ActionsManager(this);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}

	}	
	private void createMenu(){
		JMenuBar menuBar = new JMenuBar();
		
		JMenu file = new JMenu("File");
		file.add(new JMenuItem(actionsManager.newGraphAction));
		file.addSeparator();
		file.add(new JMenuItem(actionsManager.loadGraphAction));
		file.add(new JMenuItem(actionsManager.saveGraphAction));
		file.addSeparator();
		file.add(new JMenuItem(actionsManager.loadSimulationAction));
		file.add(new JMenuItem(actionsManager.saveSimulationAction));
		file.addSeparator();
		file.add(new JMenuItem(actionsManager.exitAction));
		menuBar.add(file);
		
		JMenu graph = new JMenu("Graph");
		graph.add(new JMenuItem(actionsManager.generateGraphAction));
		graph.add(new JMenuItem(actionsManager.autoLayoutAction));
		graph.addSeparator();
		graph.add(new JMenuItem(actionsManager.startEditingAction));
		graph.add(new JMenuItem(actionsManager.finishEditingAction));
		menuBar.add(graph);
		
		JMenu simulation = new JMenu("Simulation");
		simulation.add(new JMenuItem(actionsManager.newSimulationAction));
		menuBar.add(simulation);
		
		JMenu view = new JMenu("View");
		for(final LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()){
			JMenuItem item = new JMenuItem(info.getName());
			item.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent arg0) {
					try {
						UIManager.setLookAndFeel(info.getClassName());
						SwingUtilities.updateComponentTreeUI(MainFrame.this);
					} catch (Exception e) {
						e.printStackTrace();
					}
					
				}
			});
			view.add(item);
		}
		menuBar.add(view);
		
		JMenu help = new JMenu("Help");		
		help.add(new JMenuItem(actionsManager.aboutAction));
		menuBar.add(help);
		setJMenuBar(menuBar);
	}	
	private void createContent(){
		JPanel parent = new JPanel(new BorderLayout());
		add(parent);
		
		optionsTabbedPane = new JTabbedPane();
		optionsTabbedPane.setPreferredSize(new Dimension(300, 100));
		parent.add(optionsTabbedPane, BorderLayout.WEST);
		graphPanel = new GraphPanel(this);
		simulationPanel = new SimulationPanel(this);
		summaryPanel =  new SummaryPanel(this);
		optionsTabbedPane.addTab("Graph", graphPanel);
		optionsTabbedPane.addTab("Simulation", simulationPanel);
		optionsTabbedPane.addTab("Summary", summaryPanel);
		
		mainPanel = new JPanel(new BorderLayout());
		graphDisplPanel = new GraphDisplPanel(this);
		agentSummaryDetailsPanel = new AgentSummaryDetailsPanel(this);
		mainPanel.add(graphDisplPanel, BorderLayout.CENTER);
		loggingPanel = new LoggingPanel();
		loggingPanel.setBorder(BorderFactory.createTitledBorder("Logging Console"));
		loggingPanel.setPreferredSize(new Dimension(100, 90));
		mainPanel.add(loggingPanel, BorderLayout.SOUTH);
		parent.add(mainPanel, BorderLayout.CENTER);
		
		JPanel bottom = new JPanel(new BorderLayout());		
		parent.add(bottom, BorderLayout.SOUTH);
	}
	public void save(File f) throws IOException{
		mxGraph graph = GraphEditor.getInstance().getGraph();

		mxGraph graph2 = new mxGraph();
		graph2.addCells(graph.cloneCells(graph.getChildCells(graph.getDefaultParent())));
		graph2.setCellStyles(mxConstants.STYLE_FILLCOLOR, null, graph2.getChildVertices(graph2.getDefaultParent()));
		
		// Creates the image for the PNG file
		BufferedImage image = mxCellRenderer.createBufferedImage(graph2,
				null, 1.0, Color.white, true, null, graphDisplPanel.getGraphComponent().getCanvas());

		// Creates the URL-encoded XML data
		mxCodec codec = new mxCodec();
		String xml = URLEncoder.encode(mxXmlUtils.getXml(codec.encode(graph2.getModel())), "UTF-8");
		mxPngEncodeParam param = mxPngEncodeParam.getDefaultEncodeParam(image);
		param.setCompressedText(new String[] { "mxGraphModel", xml });

		// Saves as a PNG file
		FileOutputStream outputStream = new FileOutputStream(f);
		try{
			mxPngImageEncoder encoder = new mxPngImageEncoder(outputStream, param);

			if (image != null){
				encoder.encode(image);

			}
		}
		finally
		{
			outputStream.close();
		}
	}
	public mxGraph load(File f) throws IOException{
		mxGraph graph = null;
		Map<String, String> text = mxPngTextDecoder.decodeCompressedText(new FileInputStream(f));
		if (text != null){
			String value = text.get("mxGraphModel");

			if (value != null){
				Document document = mxXmlUtils.parseXml(URLDecoder.decode(value, "UTF-8"));
				mxCodec codec = new mxCodec(document);
				graph = new mxGraph();
				codec.decode(document.getDocumentElement(), graph.getModel());
			}
		}
		GraphEditor.getInstance().setGraph(graph);
		PlatformManager.getInstatnce().getSimulation().setGraph(GraphEditor.getInstance().getGraphModel());
		return graph;
	}
	public GraphPanel getGraphPanel() {
		return graphPanel;
	}
	public SimulationPanel getSimulationPanel() {
		return simulationPanel;
	}
	public SummaryPanel getSummaryPanel() {
		return summaryPanel;
	}
	public GraphDisplPanel getGraphDisplPanel() {
		return graphDisplPanel;
	}
	public void shutDown(){
		try {
			PrintWriter out = new PrintWriter(viewConfig);
			Properties properties = new Properties();
			properties.setProperty("mainFrame.width", getWidth() + "");
			properties.setProperty("mainFrame.height", getHeight() + "");
			properties.setProperty("mainFrame.laf", UIManager.getLookAndFeel().getClass().getName());
			properties.store(out, "");
		} catch (IOException e) {
			e.printStackTrace();
		}		
		System.exit(1);
	}
	public ActionsManager getActionsManager(){
		return actionsManager;
	}
	public LoggingPanel getLoggingPanel(){
		return loggingPanel;
	}
	public void showSummary(){
		optionsTabbedPane.setSelectedComponent(summaryPanel);
	}
	public void replaceOnMainPanel(Component oldComp, Component newComp){
		mainPanel.remove(oldComp);
		mainPanel.add(newComp);
		mainPanel.revalidate();
		mainPanel.repaint();
	}
	public AgentSummaryDetailsPanel getAgentSummaryDetailsPanel(){
		return agentSummaryDetailsPanel;
	}
	
	public void windowClosing(WindowEvent arg0) {
		shutDown();
	}
	@Override
	public void windowActivated(WindowEvent arg0) {}
	@Override
	public void windowClosed(WindowEvent arg0) {}	
	@Override
	public void windowDeactivated(WindowEvent arg0) {}	
	@Override
	public void windowDeiconified(WindowEvent arg0) {}	
	@Override
	public void windowIconified(WindowEvent arg0) {}
	@Override
	public void windowOpened(WindowEvent arg0) {}
	public void loadSimulation(File f) throws IOException{
		String fName = f.getAbsolutePath();
		File graphFile = null;
		if(fName.endsWith(".xml")){
			graphFile = new File(fName.substring(0, fName.length() - ".xml".length()) + ".png");
		}else{
			graphFile = new File(fName + ".png");
		}		
		PlatformManager.getInstatnce().newSimulation();
		mxGraph graph = mainFrame.load(graphFile);		
		GraphEditor.getInstance().setGraph(graph);
		PersistenceManager manager = PersistenceManager.getInstance();
		manager.loadSimulationFromXml(f);
	}
	public void saveSimulation(File f) throws IOException{
		File graphFile = null;
		File simFile = null;
		String fName = f.getAbsolutePath();
		if(fName.endsWith(".xml")){
			simFile = f;
			graphFile = new File(fName.substring(0, fName.length() - ".xml".length()) + ".png");
		}else{
			simFile = new File(fName + ".xml");
			graphFile = new File(fName + ".png");
		}
		save(graphFile);
		PersistenceManager manager = PersistenceManager.getInstance();
		manager.saveSimulation2Xml(simFile);
	}
	
	
}
